/***************************************************
*		 Copyright (c) 2018 MINE 田宇
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2 of the GNU General Public
* License as published by the Free Software Foundation.
*
***************************************************/

#ifndef __AHCI_H__

#define __AHCI_H__

#include "block.h"

//////FIS Type value assignments
#define	AHCI_FIS_TYPE_HOST2DEVICE_FIS		0x27
#define	AHCI_FIS_TYPE_DEVICE2HOST_FIS		0x34
#define	AHCI_FIS_TYPE_DMA_ACTIVE_FIS		0x39
#define	AHCI_FIS_TYPE_DMA_SETUP_FIS		0x41
#define	AHCI_FIS_TYPE_DATA_FIS			0x46
#define	AHCI_FIS_TYPE_BIST_ACTIVE_FIS		0x58
#define	AHCI_FIS_TYPE_PIO_SETUP_FIS		0x5F
#define	AHCI_FIS_TYPE_SET_DEVICE_BIT_FIS	0xA1

struct Generic_Host_Control
{
	unsigned int CAP;	//Host Capabilities
	unsigned int GHC;	//Global Host Control
	unsigned int IS;	//Interrupt Status
	unsigned int PI;	//Ports Implemented
	unsigned int VS;	//Version
	unsigned int CCC_CTL;	//Command Completion Coalescing Control
	unsigned int CCC_PORTs;	//Command Completion Coalsecing Ports
	unsigned int EM_LOC;	//Enclosure Management Location
	unsigned int EM_CTL;	//Enclosure Management Control
	unsigned int CAP2;	//Host Capabilities Extended
	unsigned int BOHC;	//BIOS/OS Handoff Control and Status
}__attribute__((packed));

struct Port_X_Control_Registers
{
	unsigned int PxCLB;		//Port x Command List Base Address
	unsigned int PxCLBU;		//Port x Command List Base Address Upper 32-Bits
	unsigned int PxFB;		//Port x FIS Base Address
	unsigned int PxFBU;		//Port x FIS Base Address Upper 32-Bits

	unsigned int PxIS;		//Port x Interrupt Status
	unsigned int PxIE;		//Port x Interrupt Enable
	unsigned int PxCMD;		//Port x Command and Status
	unsigned int Reserved0;		//Reserved

	unsigned int PxTFD;		//Port x Task File Data
	unsigned int PxSIG;		//Port x Signature
	unsigned int PxSSTS;		//Port x Serial ATA Status (SCR0: SStatus)
	unsigned int PxSCTL;		//Port x Serial ATA Control (SCR2: SControl)

	unsigned int PxSERR;		//Port x Serial ATA Error (SCR1: SError)
	unsigned int PxSACT;		//Port x Serial ATA Active (SCR3: SActive)
	unsigned int PxCI;		//Port x Command Issue
	unsigned int PxSNTF;		//Port x Serial ATA Notification (SCR4: SNotification)

	unsigned int PxFBS;		//Port x FIS-based Switching Control
	unsigned int PxDEVSLP;		//Port x Device Sleep
	unsigned int Reserved1[10];	//Reserved
	unsigned long PxVS[2];		//Port x Vendor Specific
}__attribute__((packed));

struct HBA_Memory_Registers
{
	struct PCI_Header_00 *PCI_Dev;
	struct Generic_Host_Control *GHC;
	struct Port_X_Control_Registers *PxCR;
}__attribute__((packed));

/*	DMA Setup – Device to Host FIS or Host to Device FIS (bidirectional),FIS Type (41h)	*/

struct DsFIS
{
	unsigned char	FIS_Type;
	unsigned char	PM_Port:4,
			 :1,
			D:1,
			I:1,
			A:1;
	unsigned char	reserved0[2];

	unsigned long	DMA_Buffer_ID;

	unsigned int	reserved1;

	unsigned int	DMA_Buffer_Offset;

	unsigned int	DMA_Transfer_Count;

	unsigned int	reserved2;
}__attribute__((packed));

/*	PIO Setup – Device to Host FIS,FIS Type (5Fh)	*/

struct PsFIS
{
	unsigned char	FIS_Type;
	unsigned char	PM_Port:4,
			 :1,
			D:1,
			I:1,
			 :1;
	unsigned char	Status;
	unsigned char	Error;

	unsigned char	LBA0;
	unsigned char	LBA1;
	unsigned char	LBA2;
	unsigned char	Device;

	unsigned char	LBA3;
	unsigned char	LBA4;
	unsigned char	LBA5;
	unsigned char	reserved0;

	unsigned short	Count;
	unsigned char	reserved1;
	unsigned char	E_Status;

	unsigned short	Transfer_count;
	unsigned short	reserved2;	
}__attribute__((packed));

/*	Register Host to Device FIS,FIS Type (27h)	*/

struct H2DFIS
{
	unsigned char	FIS_Type;
	unsigned char	PM_Port:4,
			 :3,
			C:1;
	unsigned char	Command;
	unsigned char	Features0;

	unsigned char	LBA0;
	unsigned char	LBA1;
	unsigned char	LBA2;
	unsigned char	Device;

	unsigned char	LBA3;
	unsigned char	LBA4;
	unsigned char	LBA5;
	unsigned char	Features1;

	unsigned short	Count;
	unsigned char	ICC;
	unsigned char	Control;

	unsigned int	reserved;
}__attribute__((packed));

/*	Register Device to Host FIS,FIS Type (34h)	*/

struct D2HFIS
{
	unsigned char	FIS_Type;
	unsigned char	PM_Port:4,
			 :2,
			I:1,
			 :1;
	unsigned char	Status;
	unsigned char	Error;

	unsigned char	LBA0;
	unsigned char	LBA1;
	unsigned char	LBA2;
	unsigned char	Device;

	unsigned char	LBA3;
	unsigned char	LBA4;
	unsigned char	LBA5;
	unsigned char	reserved0;

	unsigned short	Count;
	unsigned short	reserved1;

	unsigned int	reserved2;
}__attribute__((packed));

/*	Set Device Bits - Device to Host FIS,FIS Type (A1h)	*/

struct SDBFIS
{
	unsigned char	FIS_Type;
	unsigned char	PM_Port:4,
			 :2,
			I:1,
			N:1;
	unsigned char	Status_Lo:3,
			 :1,
			Status_Hi:3,
			 :1;
	unsigned char	Error;

	unsigned int	Protocol_Specific;
}__attribute__((packed));

/*	BIST Activate FIS - bidirectional,FIS Type (58h)	*/

struct BISTFIS
{
	unsigned char	FIS_Type;
	unsigned char	PM_Port:4,
			 :4;

	unsigned char	V:1,
			 :1,
			P:1,
			F:1,
			L:1,
			S:1,
			A:1,
			T:1;
	unsigned char	reserved;

	unsigned long	Data;
}__attribute__((packed));

struct Received_FIS
{
	struct DsFIS	DMA_Setup_FIS;
	unsigned char	reserved0[4];
	struct PsFIS	PIO_Setup_FIS;
	unsigned char	reserved1[12];
	struct D2HFIS	RFIS;
	unsigned char	reserved2[4];
	struct SDBFIS	Set_Device_Bits_FIS;
	unsigned char	UFIS[64];
	unsigned char	reserved3[96];
}__attribute__((packed));

/*	Physical Region Descriptor Table	*/

struct PRDT
{
	unsigned int	DBA;
	unsigned int	DBAU;
	unsigned int	reserved;
	unsigned int	DBC:22,
			R:9,
			I:1;
}__attribute__((packed));

struct Command_Table
{
	unsigned char CMD_FIS[64];
	unsigned char CMD_APAPI[16];
	unsigned char reserved[48];
	struct PRDT CMD_PRDT[];
}__attribute__((packed));

struct Command_Table_Header
{
	unsigned int	CFL:5,
			A:1,
			W:1,
			P:1,
			R:1,
			B:1,
			C:1,
			 :1,
			PMP:4,
			PRDTL:16; 
	unsigned int	PRDBC;
	unsigned int	CTBA;
	unsigned int	CTBAU;

	unsigned int	Reserved0;
	unsigned int	Reserved1;
	unsigned int	Reserved2;
	unsigned int	Reserved3;
}__attribute__((packed));

struct Command_list
{
	struct Command_Table_Header CTBL[32];
}__attribute__((packed));

/*

*/

extern struct block_device_operation AHCI_device_operation;

void AHCI_init();

void AHCI_exit();

#endif

